#include "DeviceHelper.h"

#include <QDebug>

#include "ConfigManager.h"
#include "ConstData.h"
#include "ConstNames.h"
#include "sql/database.h"
#define REG_CALIB_STD1_TIME_YEAR 26   // 标一时间年
#define REG_CALIB_STD1_TIME_MONTH 27  // 标一时间月
#define REG_CALIB_STD1_TIME_DAY 28    // 标一时间日
#define REG_CALIB_STD1_TIME_HOUR 29   // 标一时间时
#define REG_CALIB_STD1_TIME_MIN 30    // 标一时间分
#define REG_CALIB_STD1_TIME_SEC 31    // 标一时间秒
#define REG_CALIB_STD2_TIME_YEAR 38   // 标二时间年
#define REG_CALIB_STD2_TIME_MONTH 39  // 标二时间月
#define REG_CALIB_STD2_TIME_DAY 40    // 标二时间日
#define REG_CALIB_STD2_TIME_HOUR 41   // 标二时间时
#define REG_CALIB_STD2_TIME_MIN 42    // 标二时间分
#define REG_CALIB_STD2_TIME_SEC 43    // 标二时间秒
#define REG_CALIB_STD1_CONC 65        // 标一浓度(float)
#define REG_CALIB_STD1_SIG 67         // 标一信号值(float)
#define REG_CALIB_STD2_CONC 69        // 标二浓度(float)
#define REG_CALIB_STD2_SIG 71         // 标二信号值(float)
#define REG_CHECK_STD_CONC 73         // 核查标样浓度(float)
#define REG_CHECK_RESULT 75           // 核查结果(float)
#define REG_CHECK_TIME_YEAR 79        // 核查时间年
#define REG_CHECK_TIME_MONTH 80       // 核查时间月
#define REG_CHECK_TIME_DAY 81         // 核查时间日
#define REG_CHECK_TIME_HOUR 82        // 核查时间时
#define REG_CHECK_TIME_MIN 83         // 核查时间分
#define REG_CHECK_TIME_SEC 84         // 核查时间秒
#define REG_CALIB_STD2_ABS 211        // 标二吸光度(float)
#define REG_CALIB_STD1_ABS 213        // 标一吸光度(float)

// 校准标样浓度寄存器
// 常规设备命令
enum DeviceOperate {
    DEVICE_ANALYSIS = 199,    // 水样测量
    DEVICE_ZERO_CHECK = 356,  // 零点核查
    DEVICE_STD_CHECK = 208,   // 标液核查
    DEVICE_CALIB = 355,       // 校正标定
    DEVICE_CALIB_1 = 197,     // 校正标一
    DEVICE_CALIB_2 = 198,     // 校正标二
    DEVICE_CLEAN = 207,       // 仪表清洗
    DEVICE_STOP = 209,        // 停止设备
    DEVICE_SET_TIME = 200,    // 确定校时
};
static const QMap<QString, quint16> DEVICE_OPERATE_MAP = {
    {OperationNames::NORMAL_ANALYSIS, DEVICE_ANALYSIS},
    {OperationNames::NORMAL_ZERO_CHECK, DEVICE_ZERO_CHECK},
    {OperationNames::NORMAL_STD_CHECK, DEVICE_STD_CHECK},
    {OperationNames::NORMAL_CALIB_FULL, DEVICE_CALIB},
    {OperationNames::NORMAL_CALIB_1, DEVICE_CALIB_1},
    {OperationNames::NORMAL_CALIB_2, DEVICE_CALIB_2},
    {OperationNames::NORMAL_CLEAN, DEVICE_CLEAN},
    {OperationNames::COMMON_STOP, DEVICE_STOP},
    {OperationNames::COMMON_SET_TIME, DEVICE_SET_TIME},
};

enum DeviceStatus {
    DEVICE_STATUS_RUNNING = 0,      // 运行
    DEVICE_STATUS_MAINTENANCE = 1,  // 维护
    DEVICE_STATUS_FAULT = 2,        // 故障
    DEVICE_STATUS_CALIB = 3,        // 校准
    DEVICE_STATUS_INSPECT = 4,      // 核查
    DEVICE_STATUS_ANALYSIS = 6,     // 测量
    DEVICE_STATUS_CALIBRATION = 7,  // 标定
    DEVICE_STATUS_IDLE = 8,         // 空闲
    DEVICE_STATUS_OPERATION = 9,    // 运维
    DEVICE_STATUS_OTHER = 10,       // 其他
};

// TODO
// 组态校正状态变量StateManualCalib需要改成5；需要添加DTStartCalibCmd校正命令；零点核查未实现；标一标二状态没有；校准标一开始时间没有；
static const QMap<quint16, QString> DEVICE_STATUS_MAP = {
    {DEVICE_STATUS_RUNNING, StateNames::NORMAL_STATE_RUNNING},
    {DEVICE_STATUS_MAINTENANCE, StateNames::NORMAL_STATE_MAINTENANCE},
    {DEVICE_STATUS_FAULT, StateNames::NORMAL_STATE_FAULT},
    {DEVICE_STATUS_CALIB, StateNames::NORMAL_STATE_CALIB},
    {DEVICE_STATUS_INSPECT, StateNames::NORMAL_STATE_INSPECT},
    {DEVICE_STATUS_ANALYSIS, StateNames::NORMAL_STATE_ANALYSIS},
    {DEVICE_STATUS_CALIBRATION, StateNames::NORMAL_STATE_CALIBRATION},
    {DEVICE_STATUS_IDLE, StateNames::NORMAL_STATE_IDLE},
    {DEVICE_STATUS_OPERATION, StateNames::NORMAL_STATE_OPERATION},
    {DEVICE_STATUS_OTHER, StateNames::NORMAL_STATE_OTHER},
};
/*
常规设备故障码
    0：无报警
    1：系统故障
    2：电源故障
    3：缺试剂
    4：缺蒸馏水
    5：加热故障
    6：排残液故障
    7：测量值超量程异常
    8：其他故障
    9：采集水样、试剂超时
    10：其他报警
*/
static const QMap<quint16, QString> DEVICE_FAULT_CODE_MAP = {
    {0, ErrorNames::COMMON_ERROR_NONE},
    {1, ErrorNames::NORMAL_ERROR_SYSTEM},
    {2, ErrorNames::NORMAL_ERROR_POWER},
    {3, ErrorNames::NORMAL_ERROR_REAGENT},
    {4, ErrorNames::NORMAL_ERROR_WATER},
    {5, ErrorNames::NORMAL_ERROR_HEATING},
    {6, ErrorNames::NORMAL_ERROR_WASTE_DISPOSAL},
    {7, ErrorNames::NORMAL_ERROR_OVER_RANGE},
    {8, ErrorNames::NORMAL_ERROR_OTHER},
    {9, ErrorNames::NORMAL_ERROR_REAGENT_INSUFFICIENT},
    {10, ErrorNames::NORMAL_ERROR_OTHER_ALARM},
};

/* 配置项名称映射 */
static const QVariantMap DEVICE_CONFIG_MAP = {
    {ConfigNames::NORMAL_CONFIG_RANGE_LOWER_LIMIT, 0.0},    // 量程下限浓度
    {ConfigNames::NORMAL_CONFIG_RANGE_UPPER_LIMIT, 100.0},  // 量程上限浓度
};
DeviceHelper::DeviceHelper(QString deviceName, QObject* parent) : IDevice(deviceName, parent)
{
    m_operateMap = DEVICE_OPERATE_MAP;
    m_statusMap = DEVICE_STATUS_MAP;
    m_errorMap = DEVICE_FAULT_CODE_MAP;
    m_configMap = DEVICE_CONFIG_MAP;
    loadDeviceConfig();
    qDebug() << "initialized with device name:" << m_deviceName;
}

DeviceHelper::~DeviceHelper() { qDebug() << "destroyed for device name:" << m_deviceName; }
void DeviceHelper::onGetDeviceData()
{
    if (m_busyFlags.dataBusy) {
        return;
    }
    m_busyFlags.dataBusy = true;
    ModbusHelper* modbus = ModbusManager::instance()->getModbusHelper(m_deviceName);
    if (!modbus) {
        qDebug() << "Failed to get ModbusHelper for device:" << m_deviceName;
        m_busyFlags.dataBusy = false;
        return;
    }

    if (m_dataCount % 10 == 0) onGetDeviceData2(modbus);
    m_dataCount++;

    modbus->asyncReadFloat(1, 1)
        .then([this, modbus](const QVector<float>& result) {
            if (m_deviceData.analyze_lastResult != result[0]) {
                m_deviceData.analyze_preResult = m_deviceData.analyze_lastResult;
                m_deviceData.analyze_lastResult = result[0];
                // 检测测量值是否在正常范围内
                checkMeasurementRange(result[0]);
            }
            return modbus->asyncRead(18, 2);
        })
        .then([this, modbus](const QVector<quint16>& result) {
            m_deviceData.status = result[0];
            m_isIdle = m_deviceData.status == DEVICE_STATUS_IDLE;  // 更新空闲状态

            m_deviceData.faultCode = result[1];
            if (m_deviceData.faultCode != m_lastFaultCode && m_deviceData.faultCode != 0) {
                emit errorOccurred(QString("错误: %1").arg(getErrorName(m_deviceData.faultCode)));
            }
            m_lastFaultCode = m_deviceData.faultCode;

            return modbus->asyncRead(201, 6);
        })
        .then([this](const QVector<quint16>& result) {
            QDateTime datetime(QDate(result[0], result[1], result[2]),
                               QTime(result[3], result[4], result[5]));
            m_deviceData.datetime = datetime;
            emit deviceDataChanged(m_deviceData);
        })
        .finally([this]() { m_busyFlags.dataBusy = false; });
}
void DeviceHelper::setDeviceTime(const QDateTime& datetime)
{
    if (m_busyFlags.controlBusy) {
        return;
    }
    m_busyFlags.controlBusy = true;
    ModbusHelper* modbus = ModbusManager::instance()->getModbusHelper(m_deviceName);
    if (!modbus) {
        qDebug() << "Failed to get ModbusHelper for device:" << m_deviceName;
        m_busyFlags.controlBusy = false;
        return;
    }
    QVector<quint16> data;
    data << 1 << datetime.date().year() << datetime.date().month() << datetime.date().day()
         << datetime.time().hour() << datetime.time().minute() << datetime.time().second();
    modbus->asyncWrite(200, data)
        .fail([this](const QString& error) {
            qDebug() << "Failed to write registers for device:" << m_deviceName
                     << "Error:" << error;
        })
        .finally([this]() { m_busyFlags.controlBusy = false; });
}
void DeviceHelper::control(quint16 optCode) { IDevice::control(optCode, 1); }

void DeviceHelper::onGetDeviceData2(ModbusHelper* modbus)
{
    // 读取校准和核查数据
    modbus
        ->asyncRead(REG_CALIB_STD1_TIME_YEAR, 6)  // 读取标一时间
        .then([this, modbus](const QVector<quint16>& result) {
            // 处理标一时间
            if ((result[0] > 0 && result[0] < 70) ||
                (result[0] > 2020 && result[0] < 2070)) {  // 判断年份是否有效
                QDateTime calib1Time(QDate(result[0], result[1], result[2]),
                                     QTime(result[3], result[4], result[5]));
                m_deviceData.cali1_lastDate = calib1Time;
            }

            // 读取标二时间
            return modbus->asyncRead(REG_CALIB_STD2_TIME_YEAR, 6);
        })
        .then([this, modbus](const QVector<quint16>& result) {
            // 处理标二时间
            if ((result[0] > 0 && result[0] < 70) ||
                (result[0] > 2020 && result[0] < 2070)) {  // 判断年份是否有效
                QDateTime calib2Time(QDate(result[0], result[1], result[2]),
                                     QTime(result[3], result[4], result[5]));
                m_deviceData.cali2_lastDate = calib2Time;
            }

            // 读取核查时间
            return modbus->asyncRead(REG_CHECK_TIME_YEAR, 6);
        })
        .then([this, modbus](const QVector<quint16>& result) {
            // 处理核查时间
            if ((result[0] > 0 && result[0] < 70) ||
                (result[0] > 2020 && result[0] < 2070)) {  // 判断年份是否有效
                QDateTime inspectionTime(QDate(result[0], result[1], result[2]),
                                         QTime(result[3], result[4], result[5]));
                m_deviceData.inspect_std_lastDate = inspectionTime;
            }

            // 读取校准相关的浓度数据
            return modbus->asyncReadFloat(REG_CALIB_STD1_CONC,
                                          4);  // 标一浓度、标一信号值、标二浓度、标二信号值
        })
        .then([this, modbus](const QVector<float>& result) {
            m_deviceData.cali_std1_conc = result[0];    // 标一浓度
            m_deviceData.cali1_lastResult = result[1];  // 标一信号值
            m_deviceData.cali_std2_conc = result[2];    // 标二浓度
            m_deviceData.cali2_lastResult = result[3];  // 标二信号值

            // 读取标一和标二的吸光度值
            return modbus->asyncReadFloat(REG_CALIB_STD2_ABS, 2);  // 标二吸光度、标一吸光度
        })
        .then([this, modbus](const QVector<float>& result) {
            m_deviceData.cali2_absorbance = result[0];  // 标二吸光度
            m_deviceData.cali1_absorbance = result[1];  // 标一吸光度

            // 读取核查相关数据
            return modbus->asyncReadFloat(REG_CHECK_STD_CONC, 2);  // 核查标样浓度、核查结果
        })
        .then([this](const QVector<float>& result) {
            m_deviceData.inspect_std_conc = result[0];        // 核查标样浓度
            m_deviceData.inspect_std_lastResult = result[1];  // 核查结果

            // 检查时间变化并记录
            checkAndRecordCalibration();
            checkAndRecordInspection();
        });
}

void DeviceHelper::checkAndRecordCalibration()
{
    // 检查标一校准时间变化
    if (m_deviceData.cali1_lastDate.isValid() && m_deviceData.cali1_lastDate != m_lastCalib1Time) {
        qDebug() << "检测到标一校准时间变化:" << m_deviceData.cali1_lastDate;

        // 插入标一校准记录
        Database::insertCalibrationRecord(m_deviceName, "standard_1",
                                          m_deviceData.cali_std1_conc,    // 标一浓度
                                          m_deviceData.cali1_lastResult,  // 标一信号值
                                          m_deviceData.cali1_lastDate,
                                          m_deviceData.cali1_absorbance);  // 标一吸光度

        m_lastCalib1Time = m_deviceData.cali1_lastDate;
    }

    // 检查标二校准时间变化
    if (m_deviceData.cali2_lastDate.isValid() && m_deviceData.cali2_lastDate != m_lastCalib2Time) {
        qDebug() << "检测到标二校准时间变化:" << m_deviceData.cali2_lastDate;

        // 插入标二校准记录
        Database::insertCalibrationRecord(m_deviceName, "standard_2",
                                          m_deviceData.cali_std2_conc,    // 标二浓度
                                          m_deviceData.cali2_lastResult,  // 标二信号值
                                          m_deviceData.cali2_lastDate,
                                          m_deviceData.cali2_absorbance);  // 标二吸光度

        m_lastCalib2Time = m_deviceData.cali2_lastDate;
    }
}

void DeviceHelper::checkAndRecordInspection()
{
    // 检查核查时间变化
    if (m_deviceData.inspect_std_lastDate.isValid() &&
        m_deviceData.inspect_std_lastDate != m_lastInspectionTime) {
        qDebug() << "检测到核查时间变化:" << m_deviceData.inspect_std_lastDate;

        // 插入核查记录
        Database::insertInspectionRecord(m_deviceName,
                                         "std_check",                          // 标液核查
                                         m_deviceData.inspect_std_conc,        // 标准浓度
                                         m_deviceData.inspect_std_lastResult,  // 测量浓度
                                         m_deviceData.inspect_std_lastDate);

        m_lastInspectionTime = m_deviceData.inspect_std_lastDate;
    }
}

void DeviceHelper::loadDeviceConfig()
{
    // 加载设备配置
    ConfigManager* config = ConfigManager::instance();
    config->loadConfig();

    QJsonObject root = config->getSection("DeviceConfig");
    QJsonObject json = root.value(m_deviceName).toObject();
    if (json.isEmpty()) {
        qDebug() << "No device config found for:" << m_deviceName;
        return;
    }
    m_configMap[ConfigNames::NORMAL_CONFIG_RANGE_LOWER_LIMIT] =
        json.value(ConfigNames::NORMAL_CONFIG_RANGE_LOWER_LIMIT).toDouble();
    m_configMap[ConfigNames::NORMAL_CONFIG_RANGE_UPPER_LIMIT] =
        json.value(ConfigNames::NORMAL_CONFIG_RANGE_UPPER_LIMIT).toDouble();
}
bool DeviceHelper::saveDeviceConfig(const QVariantMap& configMap)
{
    // 保存设备配置
    ConfigManager* configManager = ConfigManager::instance();

    // 先获取现有的DeviceConfig部分，避免覆盖其他设备的配置
    QJsonObject root = configManager->getSection("DeviceConfig");

    // 构建当前设备的配置
    QJsonObject json;
    json[ConfigNames::NORMAL_CONFIG_RANGE_LOWER_LIMIT] =
        configMap[ConfigNames::NORMAL_CONFIG_RANGE_LOWER_LIMIT].toDouble();
    json[ConfigNames::NORMAL_CONFIG_RANGE_UPPER_LIMIT] =
        configMap[ConfigNames::NORMAL_CONFIG_RANGE_UPPER_LIMIT].toDouble();

    // 只更新当前设备的配置部分
    root[m_deviceName] = json;
    configManager->setSection("DeviceConfig", root);
    bool result = configManager->saveConfig();
    if (result) {
        // 保存成功后更新内部配置映射
        m_configMap = configMap;
    }
    return result;
}

void DeviceHelper::checkMeasurementRange(float value)
{
    // 获取配置的上下限
    float lowerLimit = getConfigByName(ConfigNames::NORMAL_CONFIG_RANGE_LOWER_LIMIT).toFloat();
    float upperLimit = getConfigByName(ConfigNames::NORMAL_CONFIG_RANGE_UPPER_LIMIT).toFloat();

    // 检查测量值是否在正常范围内
    if (value < lowerLimit || value > upperLimit) {
        qDebug() << m_deviceName << "测量值超出范围:" << value << "范围:[" << lowerLimit << ","
                 << upperLimit << "]";
        emit measurementOutOfRange(m_deviceName, value, lowerLimit, upperLimit);
    }
}